package com.bto.solar.work.fdd;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.bto.solar.work.common.BizException;
import com.bto.solar.work.dao.IFddTaskService;
import com.bto.solar.work.dao.IOrderBaseService;
import com.bto.solar.work.entity.FddTask;
import com.bto.solar.work.entity.OrderBase;
import com.bto.solar.work.utils.NullUtils;
import com.bto.solar.work.utils.StringUtils;
import com.fasc.open.api.utils.crypt.FddCryptUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 王小波
 * @description: 法大大回调事件处理
 * @date 2023/7/19 8:03
 */


@Slf4j
@Service
public class BtoFddNotifyService {
    @Value("${fdd.app-secret}")
    private String appSecret;

    @Autowired
    private IFddTaskService fddTasksService;
    @Autowired
    private FddService fddService;
    @Autowired
    private IOrderBaseService ordersService;


    /**
    *  将法大大回调事件转发给城北
    */
    @Async
    public String fddNotifyChengBeiSystem(HttpHeaders headers, String bizContent) {

            HttpRequest request = HttpRequest.post("http://biz.btowork.top/api/notify/fdd?bizContent="+bizContent);
//            headers.toSingleValueMap().forEach(request::header);
        try {
            HttpResponse response = request.execute();
            log.info("转发城北，返回结果\n {}" , JSON.toJSONString(response));
            return response.body();
        }
        catch (Exception e){
            return "{\"msg\":\"failed\"}\n";
        }

    }


    public boolean fddNotify(HttpHeaders headers, String bizContent) {
        String event = headers.getFirst("X-FASC-Event");
        if (StringUtils.isEmpty(event)) {
            throw new BizException("未知的回调事件类型【{}】", event);
        }
        log.info("处理法大大回调事件 {}", event);

        //处理签署相关的回调事件
        if (event.contains("sign-task-")) {
            return customerSignTaskEvent(bizContent);
        }

        return false;
    }

    /**
     * 客户签署任务事件
     * 签署事件 - https://dev.fadada.com/api-doc/HZRSAZQXZR/0T8MZCFRRZTU646K/5-1
     * 事件状态 - https://dev.fadada.com/api-help/ACJJHJQUCG/QBHKD80O7Y4QAHA3
     * notifyUrlVerify
     * sign-task-start
     * sign-task-joined
     * sign-task-read
     * sign-task-filled
     * sign-task-signed
     * sign-task-finished
     */
    private boolean customerSignTaskEvent(String bizContent) {
        log.info("sign task bizContent=" + bizContent);
        JSONObject signTaskEvent = JSONObject.parseObject(bizContent);
        String eventTime = signTaskEvent.getString("eventTime");
        String signTaskId = signTaskEvent.getString("signTaskId");
        String signTaskStatus = signTaskEvent.getString("signTaskStatus");
        String transReferenceId = signTaskEvent.getString("transReferenceId");
        if (StringUtils.isAnyBlank(eventTime, signTaskId, signTaskStatus)) {
            throw new BizException("签署任务回调，数据错误。。。signTaskId {} , signTaskStatus {}", signTaskId, signTaskStatus);
        }
        /**
         签署任务状态目前有以下几种：
         task_created: 任务创建中 (签署任务创建中，未提交)
         fill_progress: 填写进行中 (签署任务正在进行协同填写流程阶段，必填控件尚未填完)
         fill_completed: 填写已完成 (签署任务文档中所有的必填控件均已填写，但文档尚未定稿)
         sign_progress: 签署进行中 (签署任务正在进行签署流程阶段)
         sign_completed: 签署已完成 (签署任务所有参与方均已签署完成)
         task_finished: 任务已结束 (签署任务已成功结束)
         task_terminated: 任务异常停止 (签署任务已经因为某种原因而停止运行，如因为某方拒填或拒签、撤销、超期)。
         abolishing：作废中
         revoked：已作废
         */
        FddTask fddTask = fddTasksService.lambdaQuery().eq(FddTask::getSignTaskId, signTaskId).one();
        if (NullUtils.isNull(fddTask)) {
            log.error("fdd_tasks  表无法找到，法大大回调，签署完成 的 signTaskId {}", signTaskId);
        } else {
            fddTask.setSignTaskStatus(signTaskStatus);
            fddTasksService.updateById(fddTask);
            //需要处理的事件
            List<String> handEvents = Arrays.asList("task_finished", "revoked");
            if (handEvents.contains(signTaskStatus)) {

                String updateOrderSignState = null;

                if ("task_finished".equals(signTaskStatus)) {
                    updateOrderSignState = signTaskId;
                } else if ("revoked".equals(signTaskStatus)) {
                    updateOrderSignState = "revoked";
                }
                return ordersService.lambdaUpdate()
                        .eq(OrderBase::getOrderId, fddTask.getOrderId())
                        .set(OrderBase::getFddSignTaskId, updateOrderSignState).update();
            } else {
                return true;
            }
        }

        return false;
    }

    /**
     * 请求头校验
     */
    private void validatedHeader(HttpHeaders headers, String bizContent) {
        // 获取请求头参数
        String appId = headers.getFirst("X-FASC-App-Id");
        String signType = headers.getFirst("X-FASC-Sign-Type");
        String sign = headers.getFirst("X-FASC-Sign");
        String timestamp = headers.getFirst("X-FASC-Timestamp");
        //事件名称，开发者可以根据不同事件名称去解析bizContent的值，实现不同的逻辑
        String event = headers.getFirst("X-FASC-Event");
        String nonce = headers.getFirst("X-FASC-Nonce");
        //验签
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("X-FASC-App-Id", appId);
        paramMap.put("X-FASC-Sign-Type", "HMAC-SHA256");
        paramMap.put("X-FASC-Timestamp", timestamp);
        paramMap.put("X-FASC-Nonce", nonce);
        paramMap.put("X-FASC-Event", event);
        paramMap.put("bizContent", bizContent);
        //参数排序，ascii码排序
        String sortParam = FddCryptUtil.sortParameters(paramMap);
        //生成签名后可以进行校验
        String signature = null;
        try {
            signature = FddCryptUtil.sign(sortParam, timestamp, appSecret);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (!signature.equals(sign)) {
            log.error("法大大 回调请求叔叔错误");
        }
    }
}
